/*****************************************************************************
   envy24control.c - Envy24 chipset (ICE1712) control utility
   Copyright (C) 2000 by Jaroslav Kysela <perex@perex.cz>

   volume.c:  added by Takashi Iwai <tiwai@suse.de>

   (2003/03/22) Changed to hbox/vbox layout.
   Copyright (C) 2003 by Søren Wedel Nielsen
   
   (16.12.2005)  Re-worked user interface -digital mixer display permanently
   visible; pcms split to another page; controls re-arranged and all pages
   scrollable for min window size and greater flexibility; pop-up menu enabled.
   Changes to levelmeters.c to prevent invalid redraws.
   New options added: 'w' to set initial window pixel width and 't' for tall equal mixer height style.
   Copyright (C) 2005 by Alan Horstmann

   (Summer 2010) (0) After a decade, incremented version to 1.0.  (1)
   Implemented "Peak Hold" functionality in meters; reimplemented meters to
   do away with inefficient "faux LED" peak-meter display, which causes
   thousands of rectangles per-second to be drawn, individually, for no
   good reason other than increasing the load. (2) Significantly reduced
   the number of timer interrupts generated by this program by slowing down
   all updates to 10 per second -- previously meters updated 25x/second!
   (3) All volumes are represented as decibels, including the 0 to -48dB
   range of the hardware peak-meters, the 0 -to- -48dB&off attenuation for
   all inputs to the digital mixer, the 0 -to- -63dB attenuation of the
   analog DAC, and the +18 -to- -63dB attenuation/amplification of the
   analog ADC. (4) All gtk "scale" widgets have dB legends; the "PageUp"
   "PageDown" keys allow rapid movement between the marked levels, and
   "UpArrow" and "DownArrow" allow fine-adjustment.  (5) Added command-line
   options --no_scale_mark, --channel_group_modulus, --lights_color and
   --bg_color options; fixed --card and --device to allow valid ALSA card
   and CTL device names ( https://bugzilla.redhat.com/show_bug.cgi?id=602900 ).
   (6) Add display of "Delta IEC958 Input Status" under "Hardware Settings."

   Copyright (C) 2010 Niels Mayer ( http://nielsmayer.com )
   Copyright (C) 2010 - 2011 Tim E. Real (terminator356 on sourceforge)

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
******************************************************************************/

#include "globaldefs.h"
#include "envy24control.h"
#include "midi.h"
#include "config.h"
#define _GNU_SOURCE
#include <getopt.h>

int input_channels, output_channels, pcm_output_channels, spdif_channels, view_spdif_playback, card_number;
int card_is_dmx6fire = FALSE, tall_equal_mixer_ht = FALSE;
int no_scale_marks = FALSE, channel_group_modulus = 2; /* NPM added options */
GdkColor *meter_bg = NULL, *meter_fg = NULL; /* NPM added options */
int card_has_delta_iec958_input_status = FALSE; /* NPM added to support "Delta IEC958 Input Status" */
char *profiles_file_name, *default_profile;

ice1712_eeprom_t card_eeprom;
snd_ctl_t *ctl;

GtkWidget *window;

GtkWidget *mixer_mix_drawing;
GtkWidget *mixer_clear_peaks_button;
GtkWidget *mixer_drawing[20];
GtkObject *mixer_adj[20][2];
GtkWidget *mixer_vscale[20][2];
GtkWidget *mixer_label[20][2];			  /* NPM: labels for L/R dB attenuation into digital mixer: see "Monitor Inputs" and "Monitor PCMs" panels */
GtkWidget *peak_label[MULTI_TRACK_PEAK_CHANNELS]; /* NPM: labels for dBFS peaks for all inputs/outputs of digital mixer: see "Monitor Inputs" and "Monitor PCMs" panels */
GtkWidget *adc_peak_label[MAX_INPUT_CHANNELS] = {NULL, }; /* NPM: labels for dBFS peak levels of ADC inputs: see "Analog Volume" panel */
GtkWidget *dac_peak_label[MAX_OUTPUT_CHANNELS] = {NULL, }; /* NPM: labels for dBFS peak levels of DAC outputs: see "Analog Volume" panel */
GtkWidget *mixer_mute_toggle[20][2];
GtkWidget *mixer_stereo_toggle[20];

GtkWidget *router_radio[10][12];

//GtkWidget *hw_master_clock_xtal_radio;
GtkWidget *hw_master_clock_xtal_22050;
GtkWidget *hw_master_clock_xtal_32000;
GtkWidget *hw_master_clock_xtal_44100;
GtkWidget *hw_master_clock_xtal_48000;
GtkWidget *hw_master_clock_xtal_88200;
GtkWidget *hw_master_clock_xtal_96000;
GtkWidget *hw_master_clock_spdif_radio;
GtkWidget *hw_master_clock_word_radio;
GtkWidget *hw_master_clock_status_label;
GtkWidget *hw_master_clock_actual_rate_label;

GtkWidget *hw_clock_state_label;
GtkWidget *hw_clock_state_locked;
GtkWidget *hw_clock_state_reset;

GtkWidget *hw_rate_locking_check;
GtkWidget *hw_rate_reset_check;

GtkObject *hw_volume_change_adj;
GtkWidget *hw_volume_change_spin;

GtkWidget *hw_iec958_input_status_label; /* NPM */

GtkWidget *hw_spdif_profi_nonaudio_radio;
GtkWidget *hw_spdif_profi_audio_radio;

GtkWidget *hw_profi_stream_stereo_radio;
GtkWidget *hw_profi_stream_notid_radio;

GtkWidget *hw_profi_emphasis_none_radio;
GtkWidget *hw_profi_emphasis_5015_radio;
GtkWidget *hw_profi_emphasis_ccitt_radio;
GtkWidget *hw_profi_emphasis_notid_radio;

GtkWidget *hw_consumer_copyright_on_radio;
GtkWidget *hw_consumer_copyright_off_radio;

GtkWidget *hw_consumer_copy_1st_radio;
GtkWidget *hw_consumer_copy_original_radio;

GtkWidget *hw_consumer_emphasis_none_radio;
GtkWidget *hw_consumer_emphasis_5015_radio;

GtkWidget *hw_consumer_category_dat_radio;
GtkWidget *hw_consumer_category_pcm_radio;
GtkWidget *hw_consumer_category_cd_radio;
GtkWidget *hw_consumer_category_general_radio;

GtkWidget *hw_spdif_professional_radio;
GtkWidget *hw_spdif_consumer_radio;
GtkWidget *hw_spdif_output_notebook;

GtkWidget *hw_spdif_input_coaxial_radio;
GtkWidget *hw_spdif_input_optical_radio;
GtkWidget *hw_spdif_switch_off_radio;

GtkWidget *input_interface_internal;
GtkWidget *input_interface_front_input;
GtkWidget *input_interface_rear_input;
GtkWidget *input_interface_wavetable;

GtkWidget *hw_phono_input_on_radio;
GtkWidget *hw_phono_input_off_radio;

GtkObject *av_dac_volume_adj[10];
GtkObject *av_adc_volume_adj[10];
GtkObject *av_ipga_volume_adj[10];
GtkWidget *av_dac_volume_label[10];
GtkWidget *av_adc_volume_label[10];
GtkWidget *av_ipga_volume_label[10];
GtkWidget *av_dac_sense_radio[10][4];
GtkWidget *av_adc_sense_radio[10][4];

// TER: Custom marker and page up/down snapping stuff. 
SliderScale   mixer_volume_scales[20][2];
SliderScale     dac_volume_scales[10];
SliderScale     adc_volume_scales[10];
SliderScale    ipga_volume_scales[10];


struct profile_button {
	GtkWidget *toggle_button;
	GtkWidget *entry;
} profiles_toggle_buttons[MAX_PROFILES];

GtkWidget *active_button = NULL;
GtkObject *card_number_adj;

static void scale_mark_free(ScaleMark *mark)
{
  g_free((gpointer)mark->markup);
  g_free(mark);
}

void clear_all_scale_marks(gboolean init)
{
  int i, j;
  for(i = 0; i < 20; i++)
  {  
    for(j = 0; j < 2; j++)
    {  
      if(!init)
      {  
        g_slist_foreach(mixer_volume_scales[i][j].marks, (GFunc)scale_mark_free, NULL);
        g_slist_free(mixer_volume_scales[i][j].marks);
      }  
      mixer_volume_scales[i][j].marks = NULL;
      mixer_volume_scales[i][j].scale = NULL;
      mixer_volume_scales[i][j].type  = MIXER_STRIP;
      mixer_volume_scales[i][j].idx   = i;
    }  
  }
  for(i = 0; i < 10; i++)
  {  
    if(!init)
    {  
      g_slist_foreach(dac_volume_scales[i].marks, (GFunc)scale_mark_free, NULL);
      g_slist_free(dac_volume_scales[i].marks);
    }  
    dac_volume_scales[i].marks = NULL;
    dac_volume_scales[i].scale = NULL;
    dac_volume_scales[i].type  = DAC_STRIP;
    dac_volume_scales[i].idx   = i;
  }
  for(i = 0; i < 10; i++)
  {  
    if(!init)
    {  
      g_slist_foreach(adc_volume_scales[i].marks, (GFunc)scale_mark_free, NULL);
      g_slist_free(adc_volume_scales[i].marks);
    }  
    adc_volume_scales[i].marks = NULL;
    adc_volume_scales[i].scale = NULL;
    adc_volume_scales[i].type  = ADC_STRIP;
    adc_volume_scales[i].idx   = i;
  }
  for(i = 0; i < 10; i++)
  {  
    if(!init)
    {  
      g_slist_foreach(ipga_volume_scales[i].marks, (GFunc)scale_mark_free, NULL);
      g_slist_free(ipga_volume_scales[i].marks);
    }  
    ipga_volume_scales[i].marks = NULL;
    ipga_volume_scales[i].scale = NULL;
    ipga_volume_scales[i].type  = ADC_STRIP;
    ipga_volume_scales[i].idx   = i;
  }
}

static void create_mixer_frame(GtkWidget *box, int stream)
{
	GtkWidget *vbox;
	GtkWidget *vbox1;
	GtkWidget *hbox;
	GtkWidget *frame;
	GtkObject *adj;
	GtkWidget *vscale;
	GtkWidget *drawing;
	GtkWidget *toggle;
  GtkWidget *sl_hbox;
  GtkWidget *sc_draw_area;
  
  char str[64], drawname[32];

	if (stream <= MAX_PCM_OUTPUT_CHANNELS) {
		sprintf(str, "PCM Out %i", stream);
	} else if (stream <= (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS)) {
		sprintf(str, "SPDIF Out %s", stream & 1 ? "L": "R");
	} else if (card_is_dmx6fire) {
		switch (stream) {
		case 11: sprintf(str, "CD In L");break;
		case 12: sprintf(str, "CD In R");break;
		case 13: sprintf(str, "Line In L");break;
		case 14: sprintf(str, "Line In R");break;
		case 15: sprintf(str, "Phono/Mic L");break;
		case 16: sprintf(str, "Phono/Mic R");break;
		case 19: sprintf(str, "Digital In L");break;
		case 20: sprintf(str, "Digital In R");break;
		default : sprintf(str, "????");break;
		}
	} else if (stream <= (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + MAX_INPUT_CHANNELS)) {
		sprintf(str, "H/W In %i", stream - (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS));
	} else if (stream <= (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + MAX_INPUT_CHANNELS + MAX_SPDIF_CHANNELS)) {
		sprintf(str, "SPDIF In %s", stream & 1 ? "L": "R");
	} else {
		strcpy(str, "???");
	}

	frame = gtk_frame_new(str);
	gtk_widget_show(frame);
  gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);

	vbox = gtk_vbox_new(FALSE, 6);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

  // TER: Create a custom drawing area for the scale markings.
  sc_draw_area = gtk_drawing_area_new();
  gtk_widget_show(sc_draw_area);

	/*
	 * NPM: Left-channel scale widgets to adjust 24 bit attenuation of
	 * each input into ice1712's on-chip digital mixer.
	 */
	adj = gtk_adjustment_new(LOW_MIXER_ATTENUATION_VALUE, 0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE, 0); /* NPM: using step size of 12 gives -12dB step-size */
	mixer_adj[stream-1][0] = adj;
	vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
  gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw value since printing dB values via mixer_adjust() */
  mixer_vscale[stream-1][0] = vscale;
  /* NPM: above, set step size of 12 ==> -18dB step-size. Place dB-labelled markers at those locations */
  // TER: Replaced with custom drawing.
  //draw_24bit_attenuator_scale_markings(GTK_SCALE(vscale), GTK_POS_LEFT,
  //             (channel_group_modulus==1)
  //             ? TRUE
  //             : (stream%channel_group_modulus));
  gtk_widget_show(vscale);

  // TER: Create list of scale marking positions, connect handlers, then pack.
  scale_add_marks(GTK_SCALE(vscale), 
                  #ifndef HAVE_GTK_24
                  0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE, 
                  #endif                   
                  &mixer_volume_scales[stream - 1][0], GTK_POS_LEFT,
                  (channel_group_modulus==1) ? TRUE : (stream % channel_group_modulus));
  g_signal_connect(G_OBJECT(sc_draw_area), "size-request",      
                    G_CALLBACK (scale_size_req_handler), (gpointer)&mixer_volume_scales[stream - 1][0]);
  //gtk_widget_set_events(sc_draw_area, GDK_STRUCTURE_MASK); // Needed ?
  g_signal_connect(G_OBJECT(sc_draw_area), "expose_event",
                    G_CALLBACK (scale_expose_handler), (gpointer)&mixer_volume_scales[stream - 1][0]);
  gtk_widget_set_events(sc_draw_area, GDK_EXPOSURE_MASK);
  g_signal_connect(G_OBJECT(sc_draw_area), "button-press-event",
                    G_CALLBACK (scale_btpress_handler), (gpointer)&mixer_volume_scales[stream - 1][0]);
  gtk_widget_set_events(sc_draw_area, GDK_BUTTON_PRESS_MASK);
  gtk_box_pack_start(GTK_BOX(hbox), sc_draw_area, TRUE, TRUE, 0);
  
	//gtk_box_pack_start(GTK_BOX(hbox), vscale, TRUE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), vscale, TRUE, TRUE, 0); // TER
	gtk_scale_set_digits(GTK_SCALE(vscale), 0);
	gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
			   GTK_SIGNAL_FUNC(mixer_adjust),
			   (gpointer)(long)((stream << 16) + 0));

  // TER: Let us handle the page up/down snapping.
  #ifdef HAVE_GTK_26
  gtk_signal_connect(GTK_OBJECT(vscale), "change-value", 
                      GTK_SIGNAL_FUNC(slider_change_value_handler),
                      (gpointer)&mixer_volume_scales[stream - 1][0]);
  #else                    
  gtk_signal_connect(GTK_OBJECT(vscale), "key-press-event", 
                      GTK_SIGNAL_FUNC(slider_key_handler),
                      (gpointer)&mixer_volume_scales[stream - 1][0]);
  #endif                    
                      
  vbox1 = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox1);
  gtk_box_pack_start(GTK_BOX(hbox), vbox1, FALSE, FALSE, 0);

	drawing = gtk_drawing_area_new();
	mixer_drawing[stream-1] = drawing;
	sprintf(drawname, "Mixer%i", stream);
	gtk_widget_set_name(drawing, drawname);
	gtk_widget_show(drawing);
	gtk_signal_connect(GTK_OBJECT(drawing), "expose_event",
			   GTK_SIGNAL_FUNC(level_meters_expose_event), NULL);
	gtk_signal_connect(GTK_OBJECT(drawing), "configure_event",
			   GTK_SIGNAL_FUNC(level_meters_configure_event), NULL);
	gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
	gtk_widget_set_usize(drawing, 24, (60 * tall_equal_mixer_ht + 204));
  //gtk_box_pack_end(GTK_BOX(vbox1), drawing, FALSE, FALSE, 0);
  gtk_box_pack_end(GTK_BOX(vbox1), drawing, TRUE, TRUE, 0);  // TER

  // TER: Create a custom drawing area for the scale markings.
  sc_draw_area = gtk_drawing_area_new();
  gtk_widget_show(sc_draw_area);
  
	/*
	 * NPM: Right-channel scale widgets to adjust 24bit attenuation of
	 * each input into ice1712's on-chip digital mixer.
	 */
	adj = gtk_adjustment_new(LOW_MIXER_ATTENUATION_VALUE, 0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE, 0);
	mixer_adj[stream-1][1] = adj;
	vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
	gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw value since printing dB values via mixer_adjust() */
  mixer_vscale[stream-1][1] = vscale;
  // TER: Replaced with custom drawing.
  //draw_24bit_attenuator_scale_markings(GTK_SCALE(vscale), GTK_POS_RIGHT,
  //             (channel_group_modulus==1)
  //             ? FALSE
  //             : ((stream-1)%channel_group_modulus));
  gtk_widget_show(vscale);

  // TER: Create list of scale marking positions, connect handlers.
  scale_add_marks(GTK_SCALE(vscale), 
                  #ifndef HAVE_GTK_24
                  0, LOW_MIXER_ATTENUATION_VALUE, 1, MIXER_ATTENUATOR_STEP_SIZE,
                  #endif  
                  &mixer_volume_scales[stream - 1][1], GTK_POS_RIGHT,
                  (channel_group_modulus==1) ? FALSE : ((stream - 1) % channel_group_modulus));
  g_signal_connect(G_OBJECT(sc_draw_area), "size-request",   
                    G_CALLBACK (scale_size_req_handler), (gpointer)&mixer_volume_scales[stream - 1][1]);
  //gtk_widget_set_events(sc_draw_area, GDK_STRUCTURE_MASK); // Needed ?
  g_signal_connect(G_OBJECT(sc_draw_area), "expose_event",
                    G_CALLBACK (scale_expose_handler), (gpointer)&mixer_volume_scales[stream - 1][1]);
  gtk_widget_set_events(sc_draw_area, GDK_EXPOSURE_MASK);
  g_signal_connect(G_OBJECT(sc_draw_area), "button-press-event",
                    G_CALLBACK (scale_btpress_handler), (gpointer)&mixer_volume_scales[stream - 1][1]);
  gtk_widget_set_events(sc_draw_area, GDK_BUTTON_PRESS_MASK);
                            
	gtk_box_pack_start(GTK_BOX(hbox), vscale, TRUE, FALSE, 0);
	gtk_scale_set_digits(GTK_SCALE(vscale), 0);
	gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
			   GTK_SIGNAL_FUNC(mixer_adjust),
			   (gpointer)(long)((stream << 16) + 1));

  // TER: Let us handle the page up/down snapping.
  #ifdef HAVE_GTK_26
  gtk_signal_connect(GTK_OBJECT(vscale), "change-value", 
                      GTK_SIGNAL_FUNC(slider_change_value_handler),
                      (gpointer)&mixer_volume_scales[stream - 1][0]);
  #else                    
  gtk_signal_connect(GTK_OBJECT(vscale), "key-press-event", 
                      GTK_SIGNAL_FUNC(slider_key_handler),
                      (gpointer)&mixer_volume_scales[stream - 1][1]);
  #endif                    
  
  //gtk_widget_set_size_request(sc_draw_area, sc_width, -1);
  gtk_box_pack_start(GTK_BOX(hbox), sc_draw_area, TRUE, TRUE, 0); // TER
  
	/* NPM: Labels to display the retained peak levels gathered from ice1712's hardware metering */
	peak_label[stream-1] = gtk_label_new("(Off) ");
	gtk_widget_modify_font(peak_label[stream-1], pango_font_description_from_string ("Monospace"));
	gtk_widget_show(peak_label[stream-1]);
  //gtk_box_pack_start(GTK_BOX(vbox), peak_label[stream-1], TRUE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), peak_label[stream-1], FALSE, FALSE, 0); // TER
	
	hbox = gtk_hbox_new(TRUE, 0);
	gtk_widget_show(hbox);
	//gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); // TER

	/* NPM: Labels to display attenuation of Left input into digital mixer: see mixer.c:mixer_adjust() */
	mixer_label[stream-1][0] = gtk_label_new("(Off) "); /* NPM: note that all but the "(Off)" values get refreshed at startup */
	gtk_misc_set_alignment(GTK_MISC(mixer_label[stream-1][0]), 0, 0.5);
	gtk_widget_modify_font(mixer_label[stream-1][0], pango_font_description_from_string ("Monospace"));
	gtk_widget_show(mixer_label[stream-1][0]);
	//gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][0], FALSE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][0], FALSE, FALSE, 0); // TER

	/* NPM: Labels to display attenuation of Right input into digital mixer: see mixer.c:mixer_adjust() */
	mixer_label[stream-1][1] = gtk_label_new("(Off) "); /* NPM: note that all but the "(Off)" values get refreshed at startup */
	gtk_misc_set_alignment(GTK_MISC(mixer_label[stream-1][1]), 1, 0.5);
	gtk_widget_modify_font(mixer_label[stream-1][1], pango_font_description_from_string ("Monospace"));
	gtk_widget_show(mixer_label[stream-1][1]);
	//gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][1], FALSE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), mixer_label[stream-1][1], FALSE, FALSE, 0); // TER

	toggle = gtk_toggle_button_new_with_label("L/R Gang");
	mixer_stereo_toggle[stream-1] = toggle;
	gtk_widget_show(toggle);
	gtk_box_pack_end(GTK_BOX(vbox), toggle, FALSE, FALSE, 0);
	/* gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE); */
	gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
			   GTK_SIGNAL_FUNC(config_set_stereo), (gpointer)(long)(stream - 1)); /* NPM: use (long) to fix "envy24control.c:251: warning: cast to pointer from integer of different size" */

	hbox = gtk_hbox_new(TRUE, 3);
	gtk_widget_show(hbox);
	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	toggle = gtk_toggle_button_new_with_label("Mute");
	mixer_mute_toggle[stream-1][0] = toggle;
	gtk_widget_show(toggle);
	gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, TRUE, 0);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE);
	gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
			   GTK_SIGNAL_FUNC(mixer_toggled_mute),
			   (gpointer)(long)((stream << 16) + 0));

	toggle = gtk_toggle_button_new_with_label("Mute");
	mixer_mute_toggle[stream-1][1] = toggle;
	gtk_widget_show(toggle);
	gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, TRUE, 0);
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), TRUE);
	gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
			   GTK_SIGNAL_FUNC(mixer_toggled_mute),
			   (gpointer)(long)((stream << 16) + 1));
}


static void create_inputs_mixer(GtkWidget *main, GtkWidget *notebook, int page)
{
        GtkWidget *hbox;
        GtkWidget *vbox;

	GtkWidget *label;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;
	int stream;


	hbox = gtk_hbox_new(FALSE, 3);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

        label = gtk_label_new("Monitor Inputs");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook),page), 
				   label);

	/* build scrolling area */
	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(viewport), vbox);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	// TER: Changed.
  //gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

	for(stream = (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + 1); \
		stream <= input_channels + (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS); stream ++) {
		if (mixer_stream_is_active(stream)) 
			create_mixer_frame(hbox, stream);
	}
	for(stream = (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + MAX_INPUT_CHANNELS + 1); \
		stream <= spdif_channels + (MAX_PCM_OUTPUT_CHANNELS + MAX_SPDIF_CHANNELS + MAX_INPUT_CHANNELS); stream ++) {
		if (mixer_stream_is_active(stream))
			create_mixer_frame(hbox, stream);
	}
}

static void create_pcms_mixer(GtkWidget *main, GtkWidget *notebook, int page)
{
        GtkWidget *hbox;
        GtkWidget *vbox;

	GtkWidget *label;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;
	int stream;

	hbox = gtk_hbox_new(FALSE, 3);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

        label = gtk_label_new("Monitor PCMs");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook),
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook),page),
				   label);

	/* build scrolling area */
	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), 
					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(viewport), vbox);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
  // TER: Changed.
	//gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

	for(stream = 1; stream <= pcm_output_channels; stream ++) {
		if (mixer_stream_is_active(stream))
			create_mixer_frame(hbox, stream);
	}
	for(stream = (MAX_PCM_OUTPUT_CHANNELS + 1); \
		stream <= spdif_channels + MAX_PCM_OUTPUT_CHANNELS; stream ++) {
		if (mixer_stream_is_active(stream) && view_spdif_playback)
			create_mixer_frame(hbox, stream);
	}

}

static void create_router_frame(GtkWidget *box, int stream, int pos)
{
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkWidget *radiobutton;
	GtkWidget *label;
	GtkWidget *hseparator;
	GSList *group = NULL;
	char str[64], str1[64];
	int idx;
	static char *table[10] = {
		"S/PDIF In L",
		"S/PDIF In R",
		"H/W In 1",
		"H/W In 2",
		"H/W In 3",
		"H/W In 4",
		"H/W In 5",
		"H/W In 6",
		"H/W In 7",
		"H/W In 8"
	};

	if (card_is_dmx6fire)
	{
                table[0] = "Digital In L";
                table[1] = "Digital In R";
                table[2] = "CD In L";
                table[3] = "CD In R";
                table[4] = "Line In L";
                table[5] = "Line In R";
                table[6] = "Phono/Mic L";
                table[7] = "Phono/Mic R";
	}

	if (stream <= MAX_OUTPUT_CHANNELS) {
		sprintf(str, "H/W Out %i (%s)", stream, stream & 1 ? "L" : "R");
	} else if (stream == (MAX_OUTPUT_CHANNELS + 1)) {
		if (card_is_dmx6fire) {
				strcpy(str, "Digital Out (L)");
			} else {
				strcpy(str, "S/PDIF Out (L)");
				}
	} else if (stream == (MAX_OUTPUT_CHANNELS + 2)) {
		if (card_is_dmx6fire) {
				strcpy(str, "Digital Out (R)");
			} else {
				strcpy(str, "S/PDIF Out (R)");
				}
	} else {
		strcpy(str, "???");
		}
	if ((stream == MAX_PCM_OUTPUT_CHANNELS + 1) || (stream == MAX_PCM_OUTPUT_CHANNELS + 2)) {
		sprintf(str1, "S/PDIF Out (%s)", stream & 1 ? "L" : "R");
	} else { 
		sprintf(str1, "PCM Out %i", stream);
	}

	frame = gtk_frame_new(str);
	gtk_widget_show(frame);
	gtk_box_pack_start (GTK_BOX(box), frame, FALSE, FALSE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);


	vbox = gtk_vbox_new(TRUE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group, str1);
	router_radio[stream-1][0] = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)patchbay_toggled, 
			   (gpointer)(long)((stream << 16) + 0));


	hseparator = gtk_hseparator_new();
	gtk_widget_show(hseparator);
	gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, TRUE, 0);

	label = gtk_label_new("");
	gtk_widget_show(label);

	/* the digital mixer can only be routed to HW1/2 or SPDIF1/2 */
	if( (stream <= 2) /* hw1/2 */ ||
	    ((stream > MAX_OUTPUT_CHANNELS) && (stream <= MAX_OUTPUT_CHANNELS + 2)) /* spdif1/2 */
	    ) {
		radiobutton = gtk_radio_button_new_with_label(group, stream & 1 ? "Digital Mix L" : "Digital Mix R");
		router_radio[stream-1][1] = radiobutton;
		group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
		gtk_widget_show(radiobutton);
		gtk_box_pack_start(GTK_BOX(vbox), 
				    radiobutton, FALSE, FALSE, 0);
		gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
				  (GtkSignalFunc)patchbay_toggled, 
				   (gpointer)(long)((stream << 16) + 1));
	}
	else {
	  label = gtk_label_new("");
	  gtk_widget_show(label);
	  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
	}


	hseparator = gtk_hseparator_new();
	gtk_widget_show(hseparator);
	gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, TRUE, 0);


	for(idx = 2 - spdif_channels; idx < input_channels + 2; idx++) {
		radiobutton = gtk_radio_button_new_with_label(group, table[idx]);
		router_radio[stream-1][2+idx] = radiobutton;
		group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
		gtk_widget_show(radiobutton);
		gtk_box_pack_start(GTK_BOX(vbox), 
				    radiobutton, FALSE, FALSE, 0);
		gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
				  (GtkSignalFunc)patchbay_toggled, 
				   (gpointer)(long)((stream << 16) + 2 + idx));
	}
}

static void create_router(GtkWidget *main, GtkWidget *notebook, int page)
{
	GtkWidget *hbox;
	GtkWidget *label;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;
	int stream, pos;

	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_container_add(GTK_CONTAINER(notebook), scrolledwindow);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), 
				       GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

        label = gtk_label_new("Patchbay / Router");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(viewport), hbox);

	pos = 0;
	for (stream = 1; stream <= output_channels; stream++) {
		if (patchbay_stream_is_active(stream))
			create_router_frame(hbox, stream, pos++);
	}
	for (stream = MAX_OUTPUT_CHANNELS + 1; stream <= MAX_OUTPUT_CHANNELS + spdif_channels; stream++) {
		if (patchbay_stream_is_active(stream))
			create_router_frame(hbox, stream, pos++);
	}
}

static void create_master_clock(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GtkWidget *label;
	GSList *group = NULL;

	frame = gtk_frame_new("Master Clock");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);


	radiobutton = gtk_radio_button_new_with_label(group, "Int 22050");
	hw_master_clock_xtal_22050 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"22050");


	radiobutton = gtk_radio_button_new_with_label(group, "Int 32000");
	hw_master_clock_xtal_32000 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"32000");


	radiobutton = gtk_radio_button_new_with_label(group, "Int 44100");
	hw_master_clock_xtal_44100 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"44100");


	radiobutton = gtk_radio_button_new_with_label(group, "Int 48000");
	hw_master_clock_xtal_48000 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"48000");


	radiobutton = gtk_radio_button_new_with_label(group, "Int 88200");
	hw_master_clock_xtal_88200 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"88200");


	radiobutton = gtk_radio_button_new_with_label(group, "Int 96000");
	hw_master_clock_xtal_96000 = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"96000");



	radiobutton = gtk_radio_button_new_with_label(group, "S/PDIF In");
	hw_master_clock_spdif_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"SPDIF");



	if (card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010 &&
	    card_eeprom.subvendor != ICE1712_SUBDEVICE_DELTA1010LT)
		return;

	radiobutton = gtk_radio_button_new_with_label(group, "Word Clock");
	hw_master_clock_word_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)internal_clock_toggled, 
			  (gpointer)"WordClock");
	
        label = gtk_label_new("Locked");
        hw_master_clock_status_label = label;
        gtk_widget_show(label);
        gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
}

static void create_rate_state(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *hbox;
	GtkWidget *check;

	frame = gtk_frame_new("Rate State");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);

	hbox = gtk_hbox_new(TRUE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(frame), hbox);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);

	check = gtk_check_button_new_with_label("Multi Track\nRate Locking");
	hw_rate_locking_check = check;
	gtk_widget_show(check);
	gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(check), "toggled",
			  (GtkSignalFunc)rate_locking_toggled, 
			  (gpointer)"locked");


	check = gtk_check_button_new_with_label("Multi Track\nRate Reset");
	hw_rate_reset_check = check;
	gtk_widget_show(check);
	gtk_box_pack_start(GTK_BOX(hbox), check, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(check), "toggled",
			  (GtkSignalFunc)rate_reset_toggled, 
			  (gpointer)"reset");

}

static void create_actual_rate(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *label;

	frame = gtk_frame_new("Actual Rate");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);

	label = gtk_label_new("");
	hw_master_clock_actual_rate_label = label;
	gtk_widget_show(label);
	gtk_container_add(GTK_CONTAINER(frame), label);
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
	gtk_misc_set_padding(GTK_MISC(label), 6, 6);
}

static void create_volume_change(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *hbox;
	GtkObject *spinbutton_adj;
	GtkWidget *spinbutton;
	GtkWidget *label;

	frame = gtk_frame_new("Volume Change");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(frame), hbox);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);

	label = gtk_label_new("Rate");
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);

	spinbutton_adj = gtk_adjustment_new(16, 0, 255, 1, 10, 0); /* NPM: last parm changed to 0, gets rid of 'Gtk-WARNING **: GtkSpinButton: setting an
> adjustment with non-zero page size is deprecated' -- change suggested by James Morris on linux-audio-dev */
	hw_volume_change_adj = spinbutton_adj;
	spinbutton = gtk_spin_button_new(GTK_ADJUSTMENT(spinbutton_adj), 1, 0);
	gtk_widget_show(spinbutton);
	gtk_box_pack_start(GTK_BOX(hbox), spinbutton, TRUE, FALSE, 0);
	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(spinbutton), TRUE);
	gtk_signal_connect(GTK_OBJECT(spinbutton_adj), "value_changed",
			   GTK_SIGNAL_FUNC(volume_change_rate_adj), NULL);
	
}

/* NPM: Put Label in "Hardware Settings" for value of IEC958 Input Status */
static void create_iec958_input_status(GtkWidget *box)
{
  if (card_has_delta_iec958_input_status) {
	GtkWidget *frame;

	frame = gtk_frame_new("IEC958 Input Status");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);

	hw_iec958_input_status_label = gtk_label_new("input: ()");
	gtk_widget_show(hw_iec958_input_status_label);
	gtk_container_add(GTK_CONTAINER(frame), hw_iec958_input_status_label);
	}
}

static void create_spdif_output_settings_profi_data(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Data Mode");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);


	radiobutton = gtk_radio_button_new_with_label(group, "Non-audio");
	hw_spdif_profi_nonaudio_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_data_toggled, 
			  (gpointer)"Non-audio");

	radiobutton = gtk_radio_button_new_with_label(group, "Audio");
	hw_spdif_profi_audio_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_data_toggled, 
			  (gpointer)"Audio");
}

static void create_spdif_output_settings_profi_stream(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Stream");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group, "Stereophonic");
	hw_profi_stream_stereo_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_stream_toggled, 
			  (gpointer)"Stereo");

	radiobutton = gtk_radio_button_new_with_label(group, "Not indicated");
	hw_profi_stream_notid_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_stream_toggled, 
			  (gpointer)"NOTID");
}

static void create_spdif_output_settings_profi_emphasis(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Emphasis");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);


	radiobutton = gtk_radio_button_new_with_label(group, "No emphasis");
	hw_profi_emphasis_none_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_emphasis_toggled, 
			  (gpointer)"No");

	radiobutton = gtk_radio_button_new_with_label(group, "50/15us");
	hw_profi_emphasis_5015_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_emphasis_toggled, 
			  (gpointer)"5015");

	radiobutton = gtk_radio_button_new_with_label(group, "CCITT J.17");
	hw_profi_emphasis_ccitt_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_emphasis_toggled, 
			  (gpointer)"CCITT");

	radiobutton = gtk_radio_button_new_with_label(group, "Not indicated");
	hw_profi_emphasis_notid_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)profi_emphasis_toggled, 
			  (gpointer)"NOTID");
}

static void create_spdif_output_settings_profi(GtkWidget *notebook, int page)
{
	GtkWidget *hbox;
	GtkWidget *vbox;
	GtkWidget *label;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

        label = gtk_label_new("Professional");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	create_spdif_output_settings_profi_data(vbox);
	create_spdif_output_settings_profi_stream(vbox);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	create_spdif_output_settings_profi_emphasis(vbox);
}

static void create_spdif_output_settings_consumer_copyright(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Copyright");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);
	
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);


	radiobutton = gtk_radio_button_new_with_label(group, "Copyrighted");
	hw_consumer_copyright_on_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_copyright_toggled, 
			  (gpointer)"Copyright");

	radiobutton = gtk_radio_button_new_with_label(group, "Copy permitted");
	hw_consumer_copyright_off_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_copyright_toggled,
			  (gpointer)"Permitted");
}

static void create_spdif_output_settings_consumer_copy(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Copy");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group,
						      "1-st generation");
	hw_consumer_copy_1st_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_copy_toggled, 
			  (gpointer)"1st");

	radiobutton = gtk_radio_button_new_with_label(group, "Original");
	hw_consumer_copy_original_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_copy_toggled, 
			  (gpointer)"Original");
}

static void create_spdif_output_settings_consumer_emphasis(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Emphasis");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group, "No emphasis");
	hw_consumer_emphasis_none_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_emphasis_toggled, 
			  (gpointer)"No");

	radiobutton = gtk_radio_button_new_with_label(group, "50/15us");
	hw_consumer_emphasis_5015_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_emphasis_toggled, 
			  (gpointer)"5015");
}

static void create_spdif_output_settings_consumer_category(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;

	frame = gtk_frame_new("Category");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group, "DAT");
	hw_consumer_category_dat_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_category_toggled, 
			  (gpointer)"DAT");

	radiobutton = gtk_radio_button_new_with_label(group, "PCM encoder");
	hw_consumer_category_pcm_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_category_toggled, 
			  (gpointer)"PCM");

	radiobutton = gtk_radio_button_new_with_label(group, "CD (ICE-908)");
	hw_consumer_category_cd_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_category_toggled, 
			  (gpointer)"CD");

	radiobutton = gtk_radio_button_new_with_label(group, "General");
	hw_consumer_category_general_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)consumer_category_toggled, 
			  (gpointer)"General");
}

static void create_spdif_output_settings_consumer(GtkWidget *notebook, int page)
{
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *label;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 2);

	label = gtk_label_new("Consumer");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	create_spdif_output_settings_consumer_copyright(vbox);
	create_spdif_output_settings_consumer_copy(vbox);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	create_spdif_output_settings_consumer_emphasis(vbox);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	create_spdif_output_settings_consumer_category(vbox);
}

static void create_spdif_output_settings(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *radiobutton;
	GtkWidget *notebook;
	GSList *group = NULL;

	frame = gtk_frame_new("S/PDIF Output Settings");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);

	radiobutton = gtk_radio_button_new_with_label(NULL, "Professional");
	hw_spdif_professional_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(hbox), radiobutton, FALSE, FALSE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 2);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)spdif_output_toggled, 
			  (gpointer)"Professional");

	radiobutton = gtk_radio_button_new_with_label(group, "Consumer");
	hw_spdif_consumer_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(hbox), radiobutton, FALSE, FALSE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(radiobutton), 2);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)spdif_output_toggled, 
			  (gpointer)"Consumer");


	notebook = gtk_notebook_new();
	hw_spdif_output_notebook = notebook;
	gtk_widget_show(notebook);
	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);


	create_spdif_output_settings_profi(notebook, 0);
 	create_spdif_output_settings_consumer(notebook, 1); 
}

static void create_spdif_input_select(GtkWidget *box)
{
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *radiobutton;
	GSList *group = NULL;
	int hide = 1;

	if((card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTADIO2496) || (card_is_dmx6fire))
		hide = 0;

	frame = gtk_frame_new("Digital Input");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(frame), 2);

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	radiobutton = gtk_radio_button_new_with_label(group, "Coaxial");
	hw_spdif_input_coaxial_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)spdif_input_toggled, 
			  (gpointer)"Coaxial");

	radiobutton = gtk_radio_button_new_with_label(group, "Optical");
	hw_spdif_input_optical_radio = radiobutton;
	group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	gtk_widget_show(radiobutton);
	gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
	gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
			  (GtkSignalFunc)spdif_input_toggled, 
			  (gpointer)"Optical");

        radiobutton = gtk_radio_button_new_with_label(group, "Internal CD");
        hw_spdif_switch_off_radio = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
	if(card_is_dmx6fire)
	        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)spdif_input_toggled,
                          (gpointer)"Off");

        if(hide)
                gtk_widget_hide_all(frame);
}


static void create_phono_input(GtkWidget *box)
{
        GtkWidget *frame;
        GtkWidget *vbox;
        GtkWidget *radiobutton;
        GSList *group = NULL;
        int hide = 1;

        if(card_is_dmx6fire)
                hide = 0;

        frame = gtk_frame_new("Phono Input Switch");
        gtk_widget_show(frame);
        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 2);
        gtk_container_set_border_width(GTK_CONTAINER(frame), 2);

        vbox = gtk_vbox_new(FALSE, 0);
        gtk_widget_show(vbox);
        gtk_container_add(GTK_CONTAINER(frame), vbox);
        gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

        radiobutton = gtk_radio_button_new_with_label(group, "Phono");
        hw_phono_input_on_radio = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)phono_input_toggled,
                          (gpointer)"Phono");

        radiobutton = gtk_radio_button_new_with_label(group, "Mic");
        hw_phono_input_off_radio = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)phono_input_toggled,
                          (gpointer)"Mic");

        if(hide)
                gtk_widget_hide_all(frame);
}

static void create_input_interface(GtkWidget *box)
{
        GtkWidget *frame;
        GtkWidget *vbox;
        GtkWidget *radiobutton;
        GSList *group = NULL;
        int hide = 1;

        if (card_is_dmx6fire)
                hide = 0;

        frame = gtk_frame_new("Line In Selector");
        gtk_widget_show(frame);
        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, TRUE, 4);
        //gtk_container_set_border_width(GTK_CONTAINER(frame), 6);

        vbox = gtk_vbox_new(FALSE, 0);
        gtk_widget_show(vbox);
        gtk_container_add(GTK_CONTAINER(frame), vbox);
        gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

        radiobutton = gtk_radio_button_new_with_label(group, "Internal");
        input_interface_internal = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)analog_input_select_toggled,
                          (gpointer)"Internal");

        radiobutton = gtk_radio_button_new_with_label(group, "Front Input");
        input_interface_front_input = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)analog_input_select_toggled,
                          (gpointer)"Front Input");

        radiobutton = gtk_radio_button_new_with_label(group, "Rear Input");
        input_interface_rear_input = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)analog_input_select_toggled,
                          (gpointer)"Rear Input");

        radiobutton = gtk_radio_button_new_with_label(group, "Wavetable");
        input_interface_wavetable = radiobutton;
        group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
        gtk_widget_show(radiobutton);
        gtk_box_pack_start(GTK_BOX(vbox), radiobutton, FALSE, FALSE, 0);
        gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
                          (GtkSignalFunc)analog_input_select_toggled,
                          (gpointer)"Wave Table");

        if(hide)
                gtk_widget_hide_all(frame);
}

static void create_hardware(GtkWidget *main, GtkWidget *notebook, int page)
{
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *hbox1;
	GtkWidget *hbox2;
	GtkWidget *vbox;
	GtkWidget *vbox1;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

	label = gtk_label_new("Hardware Settings");
	gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	/* Build scrolling area */
	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	/* Outer box */
	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(viewport), hbox);

	/* Create boxes for controls */
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 6);

	hbox1 = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox1);
	gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);

//	hseparator = gtk_hseparator_new();
//	gtk_widget_show(hseparator);
//	gtk_box_pack_start(GTK_BOX(vbox), hseparator, FALSE, FALSE, 2);

	hbox2 = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox2);
	gtk_box_pack_start(GTK_BOX(vbox), hbox2, FALSE, FALSE, 0);

	create_master_clock(hbox1);

	vbox1 = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox1);
	gtk_box_pack_start(GTK_BOX(hbox1), vbox1, FALSE, FALSE, 20);

	create_rate_state(vbox1);
	create_actual_rate(vbox1);
	create_volume_change(vbox1);
	create_iec958_input_status(vbox1);
	create_input_interface(hbox2);
	create_phono_input(hbox2);
	create_spdif_input_select(hbox2);
	create_spdif_output_settings(hbox);
}

static void create_about(GtkWidget *main, GtkWidget *notebook, int page)
{
	GtkWidget *label;
	GtkWidget *vbox;
	GtkWidget *hbox;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

        label = gtk_label_new("About");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	/* build scrolling area */
	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);


	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(viewport), vbox);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);

	char temp_text[1024];
	sprintf(temp_text, 
		"<span size=\"large\">Envy24 Control Utility ( %s %s)</span>\n\n\
<span size=\"medium\">A GTK Tool for Envy24 PCI Audio Chip</span>\n\n\
<span size=\"small\">Copyright (C) 2000 by Jaroslav Kysela &lt;perex&#64;perex.cz&gt;</span>\n\
<span size=\"small\">Copyright (C) 2003 by Søren Wedel Nielsen</span>\n\
<span size=\"small\">Copyright (C) 2005 by Alan Horstmann</span>\n\
<span size=\"small\">Copyright (C) 2010 Niels Mayer ( http://nielsmayer.com )</span>\n\
<span size=\"small\">Copyright (C) 2010 - 2011 Tim E. Real ( terminator356 on sourceforge)</span>\n\
", VERSION, SVNVERSION);
	/* Create text as label */
	label = gtk_label_new("");
	gtk_label_set_markup(GTK_LABEL(label), temp_text);
        gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 6);
}

static void create_analog_volume(GtkWidget *main, GtkWidget *notebook, int page)
{
	GtkWidget *label;
	GtkWidget *hbox;
	GtkWidget *vbox;
	GtkWidget *frame;
	GtkObject *adj;
	GtkWidget *vscale;
	GtkWidget *radiobutton;
	GSList *group;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;
  GtkWidget *sl_hbox;
  GtkWidget *sc_draw_area;
  gdouble mn, mx;
	int i, j;
	static char* dmx6fire_inputs[6] = {
		"CD In (L)",
		"CD In (R)",
		"Line  (L)",
		"Line  (R)",
		"Phono (L)",
		"Phono (R)"
	};
	static char* dmx6fire_outputs[6] = {
		"Front (L)",
		"Front (R)",
		"Rear (L)",
		"Rear (R)",
		"Centre",
		"LFE"
	};


	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_container_add(GTK_CONTAINER(notebook), scrolledwindow);

        label = gtk_label_new("Analog Volume");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow), 
				       GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(viewport), hbox);

	/* create DAC */
	for(i = 0; i < envy_dac_volumes(); i++) {
		char name[32];
		sprintf(name, "DAC %d", i+1); /* NPM: for consistency w/ other panels, start w/ "DAC 1" */
		frame = gtk_frame_new(name);
		gtk_widget_show(frame);
		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);

		vbox = gtk_vbox_new(FALSE, 0);
		gtk_widget_show(vbox);
		gtk_container_add(GTK_CONTAINER(frame), vbox);
		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);

		/* Add friendly labels for DMX 6Fires */
		if(card_is_dmx6fire && (i < 6)){
			label = gtk_label_new(dmx6fire_outputs[i]);
			gtk_widget_show(label);
			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
		}

		/* NPM: display peak levels on DAC's in "Analog Volume" panel  */
		if (i < MAX_OUTPUT_CHANNELS) { /* make sure within bounds of dac_peak_label[] */
		  dac_peak_label[i] = label = gtk_label_new("(Off)");
		  gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
		  gtk_widget_show(label);
		  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
		}

    // TER: Create hbox for scale drawing area + slider.
    sl_hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(sl_hbox);
    gtk_box_pack_start(GTK_BOX(vbox), sl_hbox, TRUE, TRUE, 0);
    if(!get_alsa_control_range(&dac_volume_scales[i], &mn, &mx))    // TER
    {
      mn = 0;
      mx = 127;
    }  
    
		//adj = gtk_adjustment_new(0, -(envy_dac_max()), 0, 1, ANALOG_GAIN_STEP_SIZE, 0); /* NPM: using step size of 12 gives -6dB step-size */
    //adj = gtk_adjustment_new(0, mn, mx, 1, ANALOG_GAIN_STEP_SIZE, 0); // TER
    adj = gtk_adjustment_new(0, -mx, mn, 1, ANALOG_GAIN_STEP_SIZE, 0); // TER
		av_dac_volume_adj[i] = adj;
		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
		/* NPM: above, set step size of 12 ==> -6dB step-size. Place dB-labelled markers at those locations */
		// TER: Replaced with custom drawing.
    //draw_dac_scale_markings(GTK_SCALE(vscale), (i%channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT);
		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw scale value since we're displaying in dB's */
		gtk_widget_show(vscale);
    
    // TER: Create list of scale marking positions.
    scale_add_marks(GTK_SCALE(vscale), 
                    #ifndef HAVE_GTK_24
                    //mn, mx, 1, ANALOG_GAIN_STEP_SIZE,
                    -mx, mn, 1, ANALOG_GAIN_STEP_SIZE,
                    #endif 
                    &dac_volume_scales[i],  
                    (i % channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT, TRUE);
    // Create a drawing area for the scale markings.
    sc_draw_area = gtk_drawing_area_new();
    gtk_widget_show(sc_draw_area);
    // Connect size requests.
    g_signal_connect(G_OBJECT(sc_draw_area), "size-request",
                      G_CALLBACK (scale_size_req_handler), (gpointer)&dac_volume_scales[i]);
    //gtk_widget_set_events(sc_draw_area, GDK_STRUCTURE_MASK); // Needed ?
    // Handle the expose event.
    g_signal_connect(G_OBJECT(sc_draw_area), "expose_event",
                      G_CALLBACK (scale_expose_handler), (gpointer)&dac_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_EXPOSURE_MASK); // Needed?
    g_signal_connect(G_OBJECT(sc_draw_area), "button-press-event",
                      G_CALLBACK (scale_btpress_handler), (gpointer)&dac_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_BUTTON_PRESS_MASK);
    // Now pack the drawing area into the box.
    if(i % channel_group_modulus)
      gtk_box_pack_end(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    else  
      gtk_box_pack_start(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    
    //gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 0); // TER: Changed.
    if(i % channel_group_modulus)
      gtk_box_pack_start(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);
    else
      gtk_box_pack_end(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);

    gtk_scale_set_digits(GTK_SCALE(vscale), 0);
		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
				   GTK_SIGNAL_FUNC(dac_volume_adjust), 
				   (gpointer)(long)(i));

    // TER: Let us handle the page up/down snapping.
    #ifdef HAVE_GTK_26
    gtk_signal_connect(GTK_OBJECT(vscale), "change-value", 
                        GTK_SIGNAL_FUNC(slider_change_value_handler),
                        (gpointer)&dac_volume_scales[i]);
    #else                    
    gtk_signal_connect(GTK_OBJECT(vscale), "key-press-event", 
                       GTK_SIGNAL_FUNC(slider_key_handler),
                       (gpointer)&dac_volume_scales[i]);
    #endif
    
    av_dac_volume_label[i] = label = gtk_label_new("-63.5");
		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
    gtk_widget_show(label);
		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);


		if (i >= envy_dac_senses())
			continue;
		group = NULL;
		for (j = 0; j < envy_dac_sense_items(); j++) {
		  radiobutton = gtk_radio_button_new_with_label(group, 
								envy_dac_sense_enum_name(j));
			av_dac_sense_radio[i][j] = radiobutton;
			gtk_widget_show(radiobutton);
			gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
					  (GtkSignalFunc)dac_sense_toggled, 
					   (gpointer)(long)((i << 8) + j));
			gtk_box_pack_start(GTK_BOX(vbox), 
					    radiobutton, FALSE, TRUE, 0);
			group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
		}
	}

	/* create ADC */
	for (i = 0; i < envy_adc_volumes(); i++) {
		char name[32];
		sprintf(name, "ADC %d", i+1); /* NPM: for consistency w/ other panels, start w/ "ADC 1" */
		frame = gtk_frame_new(name);
		gtk_widget_show(frame);
		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);

		vbox = gtk_vbox_new(FALSE, 0);
		gtk_widget_show(vbox);
		gtk_container_add(GTK_CONTAINER(frame), vbox);
		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);

		/* Add friendly labels for DMX 6Fires */
		if(card_is_dmx6fire && (i < 6)){
			label = gtk_label_new(dmx6fire_inputs[i]);
			gtk_widget_show(label);
			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
		}

		/* NPM: display peak levels on ADC's in "Analog Volume" panel  */
		if (i < MAX_INPUT_CHANNELS) { /* make sure within bounds of adc_peak_label[] */
		  adc_peak_label[i] = label = gtk_label_new("(Off)");
		  gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
		  gtk_widget_show(label);
		  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
		}

    // TER: Create hbox for scale drawing area + slider.
    sl_hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(sl_hbox);
    gtk_box_pack_start(GTK_BOX(vbox), sl_hbox, TRUE, TRUE, 0);
    if(!get_alsa_control_range(&adc_volume_scales[i], &mn, &mx))    // TER
    {
      mn = 0;
      mx = 164;
    }  
    
		//adj = gtk_adjustment_new(0, -(envy_adc_max()), 0, 1, ANALOG_GAIN_STEP_SIZE, 0); /* using step size of 12 gives -6dB step-size */
    //adj = gtk_adjustment_new(0, mn, mx, 1, ANALOG_GAIN_STEP_SIZE, 0); // TER
    adj = gtk_adjustment_new(0, -mx, mn, 1, ANALOG_GAIN_STEP_SIZE, 0); // TER
		av_adc_volume_adj[i] = adj;
		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
		/* NPM: above, set step size of 12 ==> -6dB step-size. Place dB-labelled markers at those locations */
		// TER: Replaced with custom drawing.
    //draw_adc_scale_markings(GTK_SCALE(vscale), (i%channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT);
		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE); /* NPM: don't draw scale value since we're displaying in dB's */
		gtk_widget_show(vscale);
    
    // TER: Create list of scale marking positions.
    scale_add_marks(GTK_SCALE(vscale), 
                    #ifndef HAVE_GTK_24
                    //mn, mx, 1, ANALOG_GAIN_STEP_SIZE,
                    -mx, mn, 1, ANALOG_GAIN_STEP_SIZE,
                    #endif 
                    &adc_volume_scales[i], 
                    (i % channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT, TRUE);
    // Create a drawing area for the scale markings.
    sc_draw_area = gtk_drawing_area_new();
    gtk_widget_show(sc_draw_area);
    // Handle size requests.
    g_signal_connect(G_OBJECT(sc_draw_area), "size-request",
                      G_CALLBACK (scale_size_req_handler), (gpointer)&adc_volume_scales[i]);
    //gtk_widget_set_events(sc_draw_area, GDK_STRUCTURE_MASK); // Needed ?
    // Handle the expose event.
    g_signal_connect(G_OBJECT(sc_draw_area), "expose_event",
                      G_CALLBACK (scale_expose_handler), (gpointer)&adc_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_EXPOSURE_MASK);
    g_signal_connect(G_OBJECT(sc_draw_area), "button-press-event",
                      G_CALLBACK (scale_btpress_handler), (gpointer)&adc_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_BUTTON_PRESS_MASK);
    // Now pack the drawing area into the box.
    if(i % channel_group_modulus)
      gtk_box_pack_end(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    else  
      gtk_box_pack_start(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    
		//gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 0); // TER: Changed
    if(i % channel_group_modulus)
      gtk_box_pack_start(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);
    else
      gtk_box_pack_end(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);

    gtk_scale_set_digits(GTK_SCALE(vscale), 0);
		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
				   GTK_SIGNAL_FUNC(adc_volume_adjust), 
				   (gpointer)(long)(i));

    // TER: Let us handle the page up/down snapping.
    #ifdef HAVE_GTK_26
    gtk_signal_connect(GTK_OBJECT(vscale), "change-value", 
                        GTK_SIGNAL_FUNC(slider_change_value_handler),
                        (gpointer)&adc_volume_scales[i]);
    #else                    
    gtk_signal_connect(GTK_OBJECT(vscale), "key-press-event", 
                       GTK_SIGNAL_FUNC(slider_key_handler),
                       (gpointer)&adc_volume_scales[i]);
    #endif
    
		/* NPM */
    av_adc_volume_label[i] = label = gtk_label_new("-63.5");
		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
		gtk_widget_show(label);
		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);

		if (i >= envy_adc_senses())
			continue;
		group = NULL;
		for (j = 0; j < envy_adc_sense_items(); j++) {
			radiobutton = gtk_radio_button_new_with_label(group, 
								      envy_adc_sense_enum_name(j));
			av_adc_sense_radio[i][j] = radiobutton;
			gtk_widget_show(radiobutton);
			gtk_signal_connect(GTK_OBJECT(radiobutton), "toggled",
					  (GtkSignalFunc)adc_sense_toggled, 
					   (gpointer)(long)((i << 8) + j));
			gtk_box_pack_start(GTK_BOX(vbox), 
					    radiobutton, FALSE, TRUE, 0);
			group = gtk_radio_button_group(GTK_RADIO_BUTTON(radiobutton));
		}
	}

	/* create IPGA */
	for (i = 0; i < envy_ipga_volumes(); i++) {
		char name[32];
		sprintf(name, "IPGA %d", i);
		frame = gtk_frame_new(name);
		gtk_widget_show(frame);
		//gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
		gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
		gtk_container_set_border_width(GTK_CONTAINER(frame), 3);

		vbox = gtk_vbox_new(FALSE, 0);
		gtk_widget_show(vbox);
		gtk_container_add(GTK_CONTAINER(frame), vbox);
		gtk_container_set_border_width(GTK_CONTAINER(vbox), 3);

		/* Add friendly labels for DMX 6Fires */
		if(card_is_dmx6fire && (i < 6)){
			label = gtk_label_new(dmx6fire_inputs[i]);
			gtk_widget_show(label);
			gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
		}

    // TODO: Added ipga scale code needs TESTING on old ALSA around pre- 1.0.15. TER.
    // Create hbox for scale drawing area + slider.
    sl_hbox = gtk_hbox_new(FALSE, 0);
    gtk_widget_show(sl_hbox);
    //gtk_container_add(GTK_CONTAINER(viewport), sl_hbox);
    gtk_box_pack_start(GTK_BOX(vbox), sl_hbox, TRUE, TRUE, 0);
    if(!get_alsa_control_range(&ipga_volume_scales[i], &mn, &mx))    // TER
    {
      mn = 0;
      mx = 36;
    }  
    
		//adj = gtk_adjustment_new(0, -36, 0, 1, 6, 0);
    //adj = gtk_adjustment_new(0, mn, mx, 1, 6, 0);  // TER
    adj = gtk_adjustment_new(0, -mx, mn, 1, 6, 0);  // TER
		av_ipga_volume_adj[i] = adj;
		vscale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
		gtk_scale_set_draw_value(GTK_SCALE(vscale), FALSE);
		gtk_widget_show(vscale);

    // TER: Create list of scale marking positions.
    scale_add_marks(GTK_SCALE(vscale), 
                    #ifndef HAVE_GTK_24
                    //mn, mx, 1, 6,
                    -mx, mn, 1, 6,
                    #endif 
                    &ipga_volume_scales[i],  
                    (i % channel_group_modulus) ? GTK_POS_RIGHT : GTK_POS_LEFT, TRUE);
    // Create a drawing area for the scale markings.
    sc_draw_area = gtk_drawing_area_new();
    gtk_widget_show(sc_draw_area);
    // Handle size requests.
    g_signal_connect(G_OBJECT(sc_draw_area), "size-request",   
                      G_CALLBACK (scale_size_req_handler), (gpointer)&ipga_volume_scales[i]);
    //gtk_widget_set_events(sc_draw_area, GDK_STRUCTURE_MASK); // Needed ?
    // Handle the expose event.
    g_signal_connect(G_OBJECT(sc_draw_area), "expose_event",
                      G_CALLBACK (scale_expose_handler), (gpointer)&ipga_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_EXPOSURE_MASK);
    g_signal_connect(G_OBJECT(sc_draw_area), "button-press-event",
                      G_CALLBACK (scale_btpress_handler), (gpointer)&ipga_volume_scales[i]);
    gtk_widget_set_events(sc_draw_area, GDK_BUTTON_PRESS_MASK);
    // Now pack the drawing area into the box.
    if(i % channel_group_modulus)
      gtk_box_pack_end(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    else  
      gtk_box_pack_start(GTK_BOX(sl_hbox), sc_draw_area, TRUE, TRUE, 0);
    
    //gtk_box_pack_start(GTK_BOX(vbox), vscale, TRUE, TRUE, 3); // TER: Changed
    if(i % channel_group_modulus)
      gtk_box_pack_start(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);
    else
      gtk_box_pack_end(GTK_BOX(sl_hbox), vscale, TRUE, TRUE, 0);

    gtk_scale_set_digits(GTK_SCALE(vscale), 0);
		gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
				   GTK_SIGNAL_FUNC(ipga_volume_adjust), 
				   (gpointer)(long)(i));

    // TER: Let us handle the page up/down snapping.
    #ifdef HAVE_GTK_26
    gtk_signal_connect(GTK_OBJECT(vscale), "change-value", 
                        GTK_SIGNAL_FUNC(slider_change_value_handler),
                        (gpointer)&ipga_volume_scales[i]);
    #else                    
    gtk_signal_connect(GTK_OBJECT(vscale), "key-press-event", 
                       GTK_SIGNAL_FUNC(slider_key_handler),
                       (gpointer)&ipga_volume_scales[i]);
    #endif
    
    av_ipga_volume_label[i] = label = gtk_label_new("-63.5");
		gtk_widget_modify_font(label, pango_font_description_from_string ("Monospace"));
    gtk_widget_show(label);
		gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
	}
}

int index_active_profile()
{
	gint index;
	gboolean found;

	found = FALSE;
	for (index = 0; index < MAX_PROFILES; index++)
	{
		if (active_button == profiles_toggle_buttons[index].toggle_button) {
			found = TRUE;
			break;
		}
	}

	if (found)
		return index;

	return NOTFOUND;
}

int delete_card_number(GtkWidget *delete_button)
{
	gint res;
	gint card_nr;
	gint index;

	if (!(GTK_TOGGLE_BUTTON (delete_button)->active))
		return EXIT_SUCCESS;

  // TER: Changed. Value property is new since 2.4
	//card_nr = GTK_ADJUSTMENT (card_number_adj)->value;
  card_nr = gtk_adjustment_get_value(GTK_ADJUSTMENT(card_number_adj));
  
	if ((card_nr < 0) || (card_nr >= MAX_CARD_NUMBERS)) {
		fprintf(stderr, "card number not in [0 ... %d]\n", MAX_CARD_NUMBERS - 1);
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (delete_button), FALSE);
		return -EINVAL;
	}

	res = delete_card(card_number, profiles_file_name);
	if (res < 0) {
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (delete_button), FALSE);
		return res;
	}
	if (card_nr == card_number) {
		for (index = 0; index < MAX_PROFILES; index++)
		{
			gtk_entry_set_text(GTK_ENTRY (profiles_toggle_buttons[index].entry), get_profile_name(index + 1, card_number, profiles_file_name));
		}
	}

	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (delete_button), FALSE);

	return EXIT_SUCCESS;
}

int restore_active_profile(const gint profile_number)
{
	gint res;

	res = save_restore(ALSACTL_OP_RESTORE, profile_number, card_number, profiles_file_name, NULL);

	return res;
}

int save_active_profile(GtkWidget *save_button)
{
	gint res;
	gint index;

	if (!(GTK_TOGGLE_BUTTON (save_button)->active))
		return EXIT_SUCCESS;
	if ((index = index_active_profile()) >= 0) {
		res = save_restore(ALSACTL_OP_STORE, index + 1, card_number, profiles_file_name, \
			gtk_entry_get_text(GTK_ENTRY (profiles_toggle_buttons[index].entry)));
	} else {
		fprintf(stderr, "No active profile found.\n");
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (save_button), FALSE);
		return -EXIT_FAILURE;
	}

	gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (save_button), FALSE);

	return res;
}

void entry_toggle_editable(GtkWidget *toggle_button, GtkWidget *entry)
{
	gint index;
	gint profile_number;

	if (active_button == toggle_button) {
		gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (toggle_button), TRUE);
		gtk_editable_set_editable(GTK_EDITABLE (entry), TRUE);
		gtk_widget_grab_focus(entry);
		return;
	} else if (GTK_TOGGLE_BUTTON (toggle_button)->active) {
		active_button = toggle_button;
	}
	gtk_editable_set_editable(GTK_EDITABLE (entry), GTK_TOGGLE_BUTTON (toggle_button)->active);
	if (GTK_TOGGLE_BUTTON (toggle_button)->active) {
		gtk_widget_grab_focus(entry);
		profile_number = NOTFOUND;
		for (index = 0; index < MAX_PROFILES; index++)
		{
			if (profiles_toggle_buttons[index].toggle_button != toggle_button) {
				gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (profiles_toggle_buttons[index].toggle_button), FALSE);
			} else {
				profile_number = index + 1;
			}
		}
		if (profile_number >= 0)
			restore_active_profile(profile_number);
	}
}

void enter_callback( const GtkWidget *widget, const GtkWidget *entry )
{
	const gchar *entry_text;
	entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
	printf("Inhalt : %s\n", entry_text);
}

static GtkWidget *toggle_button_entry(const GtkWidget *parent, const gchar *profile_name, const gint index)
{
	GtkWidget *box;
	GtkWidget *entry_label;
	GtkWidget *toggle_button;

	box = gtk_hbox_new(FALSE, 0);

	toggle_button = gtk_toggle_button_new();
	gtk_container_border_width(GTK_CONTAINER(toggle_button), 3);

	profiles_toggle_buttons[index].entry = entry_label = gtk_entry_new();
	gtk_entry_set_max_length(GTK_ENTRY (entry_label), MAX_PROFILE_NAME_LENGTH);
	gtk_entry_set_text(GTK_ENTRY (entry_label), profile_name);
	/* only the active profile can be modified */
	gtk_editable_set_editable(GTK_EDITABLE (entry_label), FALSE);
	gtk_signal_connect(GTK_OBJECT (entry_label), "activate",
			 GTK_SIGNAL_FUNC (enter_callback),
			 (gpointer) entry_label);
	gtk_signal_connect(GTK_OBJECT (toggle_button), "toggled",
			 GTK_SIGNAL_FUNC (entry_toggle_editable),
			 (gpointer) entry_label);

	gtk_box_pack_start(GTK_BOX (box), entry_label, FALSE, FALSE, 20);
	gtk_widget_show(entry_label);
	gtk_widget_show(box);
	gtk_container_add(GTK_CONTAINER (toggle_button), box);
	gtk_widget_show(toggle_button);
	return (toggle_button);
}

static void create_profiles(GtkWidget *main, GtkWidget *notebook, int page)
{
	GtkWidget *label;
	GtkWidget *label_card_nr;
	GtkWidget *vbox1;
	GtkWidget *vbox2;
	GtkWidget *hbox;
	GtkWidget *hbox1;
	GtkWidget *save_button;
	GtkWidget *delete_button;
	GtkObject *card_button_adj;
	GtkWidget *card_button;
	GtkWidget *scrolledwindow;
	GtkWidget *viewport;
	gint index;
	gint profile_number;
	gchar *profile_name;
	gint max_profiles;
	gint max_digits;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);


        label = gtk_label_new("Profiles");
        gtk_widget_show(label);
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook), 
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page), 
				   label);

	/* build scrolling area */
	scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
	gtk_widget_show(scrolledwindow);
	gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow, TRUE, TRUE, 0);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
					GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_widget_show(viewport);
	gtk_container_add(GTK_CONTAINER(scrolledwindow), viewport);

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox);
	gtk_container_add(GTK_CONTAINER(viewport), hbox);
	gtk_container_set_border_width(GTK_CONTAINER(hbox), 0);


	/* Create button boxes */
	vbox1 = gtk_vbutton_box_new();

	gtk_vbutton_box_set_spacing_default(0);
	for (index = 0; index < MAX_PROFILES; index++)	{
		profile_name = get_profile_name(index + 1, card_number, profiles_file_name);
		profiles_toggle_buttons[index].toggle_button = toggle_button_entry(window, profile_name, index);
		gtk_box_pack_start(GTK_BOX (vbox1), profiles_toggle_buttons[index].toggle_button, FALSE, FALSE, 0);
	}
	gtk_widget_show(vbox1);
	gtk_container_border_width(GTK_CONTAINER(vbox1), 6);

	vbox2 = gtk_vbutton_box_new();
	gtk_widget_show(vbox2);
	gtk_container_border_width(GTK_CONTAINER(vbox2), 50);

	hbox1 = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox1);
	gtk_box_pack_start(GTK_BOX(vbox2), hbox1, FALSE, FALSE, 20);

        label_card_nr = gtk_label_new("Card Number:");
        gtk_widget_show(label_card_nr);
	gtk_box_pack_start(GTK_BOX(hbox1), label_card_nr, FALSE, FALSE, 20);
	gtk_label_set_justify(GTK_LABEL(label_card_nr), GTK_JUSTIFY_LEFT);

	card_button_adj = gtk_adjustment_new(16, 0, MAX_CARD_NUMBERS - 1, 1, 10, 0); /* NPM: set last parm to 0 to get rid of 'Gtk-WARNING **: GtkSpinButton: setting an
> adjustment with non-zero page size is deprecated' -- change suggested by James Morris on linux-audio-dev */
	card_number_adj = card_button_adj;
	card_button = gtk_spin_button_new(GTK_ADJUSTMENT (card_button_adj), 1, 0);
	gtk_widget_show(card_button);
	gtk_box_pack_start(GTK_BOX (hbox1), card_button, TRUE, FALSE, 0);
	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON (card_button), TRUE);
	gtk_adjustment_set_value(GTK_ADJUSTMENT (card_button_adj), card_number);

	delete_button = gtk_toggle_button_new_with_label("Delete card from profiles");
	gtk_widget_show(delete_button);
	gtk_box_pack_start(GTK_BOX (vbox2), delete_button, FALSE, FALSE, 20);
	gtk_signal_connect(GTK_OBJECT (delete_button), "toggled",
			 GTK_SIGNAL_FUNC (delete_card_number),
			 NULL);

	save_button = gtk_toggle_button_new_with_label("Save active profile");
	gtk_widget_show(save_button);
	gtk_box_pack_end(GTK_BOX (vbox2), save_button, FALSE, FALSE, 20);
	gtk_signal_connect(GTK_OBJECT (save_button), "toggled",
			 GTK_SIGNAL_FUNC (save_active_profile),
			 NULL);

	gtk_container_add(GTK_CONTAINER(hbox), vbox1);
	gtk_container_add(GTK_CONTAINER(hbox), vbox2);

	if (default_profile != NULL)
	{
		/*
		 * only if default_profile is numerical and lower or equal than MAX_PROFILES it will be a profile_number
		 * otherwise it will be a profile name
		 */
		if (strcspn(default_profile, "0123456789") == 0) {
			for (max_profiles = MAX_PROFILES, max_digits = 0; max_profiles > 9; max_digits++, max_profiles /= 10)
				;
			max_digits++;
			if (strlen(default_profile) <= max_digits) {
				profile_number = atoi(default_profile);
				if (profile_number < 1 || profile_number > MAX_PROFILES)
					profile_number = get_profile_number(default_profile, card_number, profiles_file_name);
			} else {
				profile_number = get_profile_number(default_profile, card_number, profiles_file_name);
			}
		} else {
			profile_number = get_profile_number(default_profile, card_number, profiles_file_name);
		}
		if ((profile_number > 0) && (profile_number <= MAX_PROFILES)) {
			gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON (profiles_toggle_buttons[profile_number - 1].toggle_button), TRUE);
		} else {
			fprintf(stderr, "Cannot find profile '%s' for card '%d'.\n", default_profile, card_number);
		}
	}
}

static void create_outer(GtkWidget *main)
{
        GtkWidget *hbox1;
        GtkWidget *vbox;

	GtkWidget *label;
	GtkWidget *frame;
	GtkWidget *drawing;

	/* Create digital mixer frame */
	vbox = gtk_vbox_new(FALSE, 1);
	gtk_widget_show(vbox);
	gtk_box_pack_start(GTK_BOX(main), vbox, FALSE, FALSE, 0);

	label = gtk_label_new("(Rt Menu) >>");
	//gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 3);
	frame = gtk_frame_new("Digital Mixer");
	gtk_widget_show(frame);
	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(frame), 1);

	/* Create controls in the digital mixer frame */

	vbox = gtk_vbox_new(FALSE, 0);
	gtk_widget_show(vbox);
	gtk_container_add(GTK_CONTAINER(frame), vbox);	

	hbox1 = gtk_hbox_new(FALSE, 0);
	gtk_widget_show(hbox1);
	gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 6);

	drawing = gtk_drawing_area_new();
	mixer_mix_drawing = drawing;
	gtk_widget_set_name(drawing, "DigitalMixer");
	gtk_box_pack_start(GTK_BOX(hbox1), drawing, TRUE, FALSE, 3);
	if (tall_equal_mixer_ht > 1 ) {
		gtk_widget_set_usize(drawing, 60, 264 + 60 * (tall_equal_mixer_ht - 1));
	} else {
		gtk_widget_set_usize(drawing, 60, 264);
	}
	gtk_signal_connect(GTK_OBJECT(drawing), "expose_event",
			   (GtkSignalFunc)level_meters_expose_event, NULL);
	gtk_signal_connect(GTK_OBJECT(drawing), "configure_event",
			   (GtkSignalFunc)level_meters_configure_event, NULL);
	gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
	gtk_widget_show(drawing);

	hbox1 = gtk_hbox_new(TRUE, 0);
	gtk_widget_show(hbox1);
	gtk_box_pack_start(GTK_BOX(vbox), hbox1, TRUE, FALSE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(hbox1), 6);

	peak_label[IDX_LMIX] = label = gtk_label_new("(Off)");
	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, TRUE, 0);

	peak_label[IDX_RMIX] = label = gtk_label_new("(Off)");
	gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
	gtk_widget_show(label);
	gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, TRUE, 0);

	mixer_clear_peaks_button = gtk_button_new_with_label("Reset Peaks");
	gtk_widget_show(mixer_clear_peaks_button);
	gtk_box_pack_start(GTK_BOX(vbox), mixer_clear_peaks_button, TRUE, FALSE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(mixer_clear_peaks_button), 4);
	gtk_signal_connect(GTK_OBJECT(mixer_clear_peaks_button), "clicked",
			   GTK_SIGNAL_FUNC(level_meters_reset_peaks), NULL);
}/* End create_outer  */

static void create_blank(GtkWidget *main, GtkWidget *notebook, int page)
{
/*	This is a little workaround for a problem with the pop-up menu.
	For some reason the label of the last page is not accessed by the menu
	so all it shows is 'page 7'.  Here a blank extra page is created, unseen,
	which seems to satisfy gtk, and we see the menu last page label correct. AH 12.7.2005 */

	GtkWidget *label;
	GtkWidget *hbox;

	hbox = gtk_hbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(notebook), hbox);

        label = gtk_label_new("Blank");
	gtk_notebook_set_tab_label(GTK_NOTEBOOK(notebook),
				   gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), page),
				   label);
}

static void usage(void)
{
	fprintf(stderr, "usage: mudita24 [-c card#] [-D control-name] [-o num-outputs] [-i num-inputs] [-p num-pcm-outputs] [-s num-spdif-in/outs] [-v] [-f profiles-file] [profile name|profile id] [-m channel-num] [-w initial-window-width] [-t height-num] [-n]\n");
	fprintf(stderr, "\t-c, --card\tAlsa card number to control\n");
	fprintf(stderr, "\t-D, --device\tcontrol-name\n");
	fprintf(stderr, "\t-o, --outputs\tLimit number of analog line outputs to display\n");
	fprintf(stderr, "\t-i, --input\tLimit number of analog line inputs to display\n");
	fprintf(stderr, "\t-p, --pcm_output\tLimit number of PCM outputs to display\n");
	fprintf(stderr, "\t-s, --spdif\tLimit number of spdif inputs/outputs to display\n");
	fprintf(stderr, "\t-v, --view_spdif_playback\tshows the spdif playback channels in the mixer\n");
	fprintf(stderr, "\t-f, --profiles_file\tuse file as profiles file\n");
	fprintf(stderr, "\t-m, --midichannel\tmidi channel number for controller control\n");
	fprintf(stderr, "\t-M, --midienhanced\tUse an enhanced mapping from midi controller to db slider\n");
	fprintf(stderr, "\t-w, --window_width\tSet initial window width (try 2,6 or 8; 280,626, or 968)\n");
	fprintf(stderr, "\t-t, --tall_eq_mixer_heights\tSet taller height mixer displays (1-9)\n");
	fprintf(stderr, "\t-n, --no_scale_mark\tDisable scale marks, which may be incorrect on certain cards (?),\n\t\t or whose Gtk-detent at the mark position may be annoying\n");
	fprintf(stderr, "\n\tThe program 'alsactl' is automatically found and used.\n\tEnvironment variable ALSACTL_PROG overrides its location.\n");
}

/* NPM for efficiency&power-savings, replaced multiple 40ms&100ms timeouts
   for each of the callbacks contained here, with a single 100ms one which
   calls gtk_timeout_add(100, (GtkFunction)envy24control_poll, ...) */
void envy24control_poll() {
  level_meters_timeout_callback(NULL);
  master_clock_status_timeout_callback(NULL);
  internal_clock_status_timeout_callback(NULL);
  rate_locking_status_timeout_callback(NULL);
  rate_reset_status_timeout_callback(NULL);
  if (card_has_delta_iec958_input_status)
    iec958_input_status_timeout_callback(NULL); /* NPM */
}

int main(int argc, char **argv)
{
  GtkWidget *notebook;
  GtkWidget *outerbox;
  char *name, tmpname[8], title[128];
  int i, c, err;
	snd_ctl_card_info_t *hw_info;
	snd_ctl_elem_value_t *val;
	int npfds;
	struct pollfd *pfds;
	int midi_fd = -1, midi_channel = -1, midi_enhanced = 0;
	int page;
	int input_channels_set = 0;
	int output_channels_set = 0;
	int pcm_output_channels_set = 0;
	int width_val;
	int wwidth_set =FALSE;
	int wwidth = 796;
	const int chanwidth = 86;
	const int fixwidth = 108;

	static struct option long_options[] = {
		{"device", 1, 0, 'D'},
		{"card", 1, 0, 'c'},
		{"profiles_file", 1, 0, 'f'},
		{"inputs", 1, 0, 'i'},
		{"midichannel", 1, 0, 'm'},
		{"midienhanced", 0, 0, 'M'},
		{"outputs", 1, 0, 'o'},
		{"pcm_outputs", 1, 0, 'p'},
		{"spdif", 1, 0, 's'},
		{"window_width", 1, 0, 'w'},
		{"view_spdif_playback", 0, 0, 'v'},
		{"tall_eq_mixer_heights", 1, 0, 't'},
		{"no_scale_mark", 1, 0, 'n'}, /* NPM: add option to disable scale marks, which may be incorrect on certain cards (?), or whose Gtk-detent behavior annoys users */
		{"channel_group_modulus", 1, 0, 'g'}, /* NPM: add optional count to control grouping behavior of labels */
		{"bg_color", 1, 0, 'b'}, /* NPM: add optional 'bg_color' for peak level metering */
		{"lights_color", 1, 0, 'l'}, /* NPM: add optional 'lights_color' for peak level metering */
		{ NULL }
	};

	snd_ctl_card_info_alloca(&hw_info);
	snd_ctl_elem_value_alloca(&val);

	/* Go through gtk initialization */
        gtk_init(&argc, &argv);

	name = NULL; /* probe */
	card_number = 0;
	input_channels = MAX_INPUT_CHANNELS;
	output_channels = MAX_OUTPUT_CHANNELS;
	pcm_output_channels = MAX_PCM_OUTPUT_CHANNELS;
	spdif_channels = MAX_SPDIF_CHANNELS;
	view_spdif_playback = 0;
	profiles_file_name = DEFAULT_PROFILERC;
	default_profile = NULL;

  clear_all_scale_marks(TRUE); // TER
  
	while ((c = getopt_long(argc, argv, "D:c:f:i:m:Mo:p:s:w:vt:ng:b:l:", long_options, NULL)) != -1) {
		switch (c) {
		case 'D':
		/*
		 * NPM: use ALSA code to fix/validate
		 * https://bugzilla.redhat.com/show_bug.cgi?id=602900
		 * The old code assumed ':' present, e.g. "-Dhw:66", (w/
		 * .asoundrc "ctl.66 {type hw, card M66}") and would
		 * coredump if given "-D66". Here, by not worrying about
		 * "hw:" and passing "optarg" as-is via 'name' to
		 * snd_ctl_open() below, resolves the issue, giving similar
		 * behavior as 'amixer'.  However, letting snd_ctl_open()
		 * validate gives less helpful error messages on
		 * failure: "envy24control -Dhw:foo"
		 *           ==> "snd_ctl_open: No such device"
		 * So validate the arg as ALSA CTL, providing
		 * a more specific error message and fail first if not valid.
		 */
			name = optarg; /* NPM: e.g. pass "-D66" unaltered to snd_ctl_open() and let it validate valid ALSA CTL name */
			if (index(optarg, ':')) { /* NPM: handle e.g. optarg == "hw:M66" */
			    card_number = snd_card_get_index(strchr(optarg, ':') + sizeof(char));
			    if (card_number < 0) {
			      fprintf(stderr, "mudita24: invalid ALSA audio device, invalid index or name for card: %s\n", optarg);
			      exit(1);
			    }
			  }
			break;
		case 'c':
	        /*
		 * NPM: use snd_card_get_index() to fix/validate
		 * https://bugzilla.redhat.com/show_bug.cgi?id=602900
		 * nb:"The accepted format is an integer value in ASCII
		 * representation or the card identifier (the id parameter
		 * for sound-card drivers). The control device name like
		 * /dev/snd/controlC0 is accepted, too."
		 */
			card_number = snd_card_get_index(optarg);
			if (card_number < 0) { /* NPM: code orig from alsa-utils/alsamixer/cli.c */
				fprintf(stderr, "mudita24: invalid ALSA index or name for audio card: %s\n", optarg);
				exit(1);
			}
			sprintf(tmpname, "hw:%d", card_number); /* e.g. "hw:M66" for arg "-cM66" passed to snd_ctl_open() below */
			name = tmpname;
			break;
		case 'f':
			profiles_file_name = optarg;
			break;
		case 'i':
			input_channels = atoi(optarg);
			if (input_channels < 0 || input_channels > MAX_INPUT_CHANNELS) {
				fprintf(stderr, "mudita24: must have 0-%i inputs\n", MAX_INPUT_CHANNELS);
				exit(1);
			}
			input_channels_set = 1;
			break;
		case 'm':
			midi_channel = atoi(optarg);
			if (midi_channel < 1 || midi_channel > 16) {
				fprintf(stderr, "mudita24: invalid midi channel number %i\n", midi_channel);
				exit(1);
			}
			--midi_channel;
			break;
		case 'M': midi_enhanced = 1; break;
		case 'o':
			output_channels = atoi(optarg);
			if (output_channels < 0 || output_channels > MAX_OUTPUT_CHANNELS) {
				fprintf(stderr, "mudita24: must have 0-%i outputs\n", MAX_OUTPUT_CHANNELS);
				exit(1);
			}
			output_channels_set = 1;
			break;
		case 'p':
			pcm_output_channels = atoi(optarg);
			if (pcm_output_channels < 0 || pcm_output_channels > MAX_PCM_OUTPUT_CHANNELS) {
				fprintf(stderr, "mudita24: must have 0-%i pcm outputs\n", MAX_PCM_OUTPUT_CHANNELS);
				exit(1);
			}
			pcm_output_channels_set = 1;
			break;
		case 's':
			spdif_channels = atoi(optarg);
			if (spdif_channels < 0 || spdif_channels > MAX_SPDIF_CHANNELS) {
				fprintf(stderr, "mudita24: must have 0-%i spdifs\n", MAX_SPDIF_CHANNELS);
				exit(1);
			}
			break;
		case 'w':
			width_val = atoi(optarg);
			if ((width_val >= 1) && (width_val <= 20)) {
				wwidth = (width_val * chanwidth + fixwidth);
			} else {
				wwidth = width_val;
			}
			wwidth_set = TRUE;
			break;
		case 'v':
			view_spdif_playback = 1;
			break;
		case 't':
			tall_equal_mixer_ht = atoi(optarg);
			if ((tall_equal_mixer_ht < 0) || (tall_equal_mixer_ht >= 10))
				tall_equal_mixer_ht = 0;
			break;
		case 'n':	/* NPM */
		        no_scale_marks = TRUE;
			break;
		case 'g':	/* NPM */
			channel_group_modulus = atoi(optarg);
			if (channel_group_modulus <= 0)
			  channel_group_modulus = 1;
			if (channel_group_modulus >= MAX_INPUT_CHANNELS)
			  channel_group_modulus = MAX_INPUT_CHANNELS;
			break;
		case 'b':	/* NPM */
		  meter_bg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
		  if (!gdk_color_parse(optarg, meter_bg)) { 
		    fprintf(stderr, "mudita24: unable to parse arguments --bg_color '%s'\n", optarg);
		    exit(1);
		  }
		  break;
		case 'l':	/* NPM */
		  meter_fg = (GdkColor *)g_malloc(sizeof(GdkColor)); /* free()'d on exit() */
		  if (!gdk_color_parse(optarg, meter_fg)) {
		    fprintf(stderr, "mudita24: unable to parse arguments --lights_color '%s'\n", optarg);
		    exit(1);
		  }
		  break;
		default:
			usage();
			exit(1);
			break;
		}
	}
	if (optind < argc) {
		default_profile = argv[optind];
	}

	if (! name) {
		/* probe cards */
		static char cardname[8];
		/* FIXME: hardcoded max number of cards */
		for (card_number = 0; card_number < 8; card_number++) {
			sprintf(cardname, "hw:%d", card_number);
			if (snd_ctl_open(&ctl, cardname, 0) < 0)
				continue;
			if (snd_ctl_card_info(ctl, hw_info) < 0 ||
			    strcmp(snd_ctl_card_info_get_driver(hw_info), "ICE1712")) {
				snd_ctl_close(ctl);
				continue;
			}
			/* found */
			name = cardname;
			break;
		}
		if (! name) {
			fprintf(stderr, "No ICE1712 cards found\n");
			exit(EXIT_FAILURE);
		}
	} else {
		if ((err = snd_ctl_open(&ctl, name, 0)) < 0) {
			fprintf(stderr, "snd_ctl_open: %s\n", snd_strerror(err));
			exit(EXIT_FAILURE);
		}
		if ((err = snd_ctl_card_info(ctl, hw_info)) < 0) {
			fprintf(stderr, "snd_ctl_card_info: %s\n", snd_strerror(err));
			exit(EXIT_FAILURE);
		}
		if (strcmp(snd_ctl_card_info_get_driver(hw_info), "ICE1712")) {
			fprintf(stderr, "invalid card type (driver is %s)\n", snd_ctl_card_info_get_driver(hw_info));
			exit(EXIT_FAILURE);
		}
	}

	snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_CARD);
	snd_ctl_elem_value_set_name(val, "ICE1712 EEPROM");
	if ((err = snd_ctl_elem_read(ctl, val)) < 0) {
		fprintf(stderr, "Unable to read EEPROM contents: %s\n", snd_strerror(err));
		exit(EXIT_FAILURE);
	}
	memcpy(&card_eeprom, snd_ctl_elem_value_get_bytes(val), 32);

	if(card_eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE)
		card_is_dmx6fire = TRUE;

	/* NPM: determine if "Delta IEC958 Input Status" available
	   excluding ICE1712_SUBDEVICE_DELTA44 since it has no IEC958 in */
	if ((card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010
	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA1010LT
	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA66
	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_AUDIOPHILE
	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTADIO2496
	     || card_eeprom.subvendor == ICE1712_SUBDEVICE_DELTA410))
	  card_has_delta_iec958_input_status = TRUE;

	/* Set a better default for input_channels and output_channels */
	if(!input_channels_set)
		if(card_is_dmx6fire)
			input_channels = 6;

	if(!output_channels_set)
		if(card_is_dmx6fire)
			output_channels = 6;

	if(!pcm_output_channels_set)
		if(card_is_dmx6fire)
			pcm_output_channels = 6; /* PCMs 7&8 can be used -set using option -p8 */

	if (!wwidth_set)
		if (card_is_dmx6fire)
			wwidth = 626;


	/* Initialize code */
	config_open();
	level_meters_init();
	mixer_init();
	patchbay_init();
	hardware_init();
	analog_volume_init();
	if (midi_channel >= 0)
		midi_fd = midi_init(argv[0], midi_channel, midi_enhanced);

	gtk_timeout_add(100, (GtkFunction)envy24control_poll, (gpointer) NULL); /* NPM for efficiency&power-savings, replaced multiple 40ms&100ms timeouts with this single one */

	fprintf(stderr, "using\t --- input_channels: %i\n\t --- output_channels: %i\n\t --- pcm_output_channels: %i\n\t --- spdif in/out channels: %i\n", \
		input_channels, output_channels, pcm_output_channels, spdif_channels);

        /* Make the title */
        sprintf(title, "Envy24 Control Utility %s (%s)", VERSION, snd_ctl_card_info_get_longname(hw_info));

        /* Create the main window */
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title(GTK_WINDOW(window), title);
        gtk_signal_connect(GTK_OBJECT (window), "delete_event", 
                           (GtkSignalFunc) gtk_main_quit, NULL);
        signal(SIGINT, (void *)gtk_main_quit);

	gtk_window_set_default_size(GTK_WINDOW(window), wwidth, 300);

	outerbox = gtk_hbox_new(FALSE, 3);
	gtk_widget_show(outerbox);
	gtk_container_add(GTK_CONTAINER(window), outerbox);

	create_outer(outerbox);

        /* Create the notebook */
        notebook = gtk_notebook_new();
	gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE);
	gtk_notebook_popup_enable(GTK_NOTEBOOK(notebook));
        gtk_widget_show(notebook);
	gtk_container_add(GTK_CONTAINER(outerbox), notebook);

	page = 0;

	create_inputs_mixer(outerbox, notebook, page++);
	create_pcms_mixer(outerbox, notebook, page++);
	create_router(outerbox, notebook, page++);
	create_hardware(outerbox, notebook, page++);
	if (envy_analog_volume_available())
		create_analog_volume(outerbox, notebook, page++);
	create_profiles(outerbox, notebook, page++);
	create_about(outerbox, notebook, page++);
	create_blank(outerbox, notebook, page++);

	npfds = snd_ctl_poll_descriptors_count(ctl);
	if (npfds > 0) {
		pfds = alloca(sizeof(*pfds) * npfds);
		npfds = snd_ctl_poll_descriptors(ctl, pfds, npfds);
		for (i = 0; i < npfds; i++)
			gdk_input_add(pfds[i].fd,
				      GDK_INPUT_READ,
				      control_input_callback,
				      ctl);
		snd_ctl_subscribe_events(ctl, 1);
	}
	if (midi_fd >= 0) {
		gdk_input_add(midi_fd, GDK_INPUT_READ, midi_process, NULL);
	}


	gtk_widget_show(window);

	level_meters_postinit();
	mixer_postinit();
	patchbay_postinit();	
	hardware_postinit();
	analog_volume_postinit();

	gtk_main();

	snd_ctl_close(ctl);
	midi_close();
	config_close();

  clear_all_scale_marks(FALSE); // TER

  return EXIT_SUCCESS;
}
